import { hexToHsva, hexToRgba } from "@uiw/react-color";
import {
  FilterDevice,
  KeyInfo,
  LightInfo,
  MacroProfile,
  KeyColor,
} from "../types/types";
import { KeyboardAPI, shiftFrom16Bit, shiftTo16Bit } from "./KeyboardAPI";
import { WebHid } from "./WebHid";
import _ from "lodash";
import { bufferToHexArray, parseColorToRGBA } from "../utils";

// 连接设备的HID接口
export const connectDeviceHID = async (
  filters: FilterDevice[] = []
): Promise<DeviceComm | undefined> => {
  const devices = await WebHid.devices(false, filters);
  if (devices.length > 1) {
    const sortDevices = devices.sort((a, b) => a.vendorId - b.vendorId);
    return new DeviceComm(new KeyboardAPI(sortDevices[0].address));
  } else if (devices.length == 1) {
    return new DeviceComm(new KeyboardAPI(devices[0].address));
  } else {
    return undefined;
  }
};

export const shiftLoFrom16Bit = (value: number): number => {
  return value & 0xff; // 使用 0xFF 而不是 255，虽然在这里两者等价，但 0xFF 更清晰地表示是8位掩码
};

export const shiftHIFrom16Bit = (value: number): number => {
  return value >> 8; // 右移8位以获取高位字节
};

// 设备通讯接口
export class DeviceComm {
  demoMode: Boolean = false;
  api: KeyboardAPI;
  vendorId: number = 0;
  productId: number = 0;
  productName: string = "Test Keyboard";
  onListeners: Array<{ name: string; fb: Function }> = [];
  mode: string = "usb";
  isMusicalGrooveEnd: boolean = false;

  onChangeDpi: ((dpi: number) => void) | undefined;

  // 添加写入状态标记
  private isWriting: boolean = false;
  private writeTimeout: NodeJS.Timeout | null = null;

  constructor(api: KeyboardAPI) {
    this.api = api;
    const hid = this.api.getHID();
    this.vendorId = hid.vendorId;
    this.productId = hid.productId;
    this.productName = hid.productName;
    this.addListeners();
  }

  addListeners() {
    const fn = (evt: HIDInputReportEvent) => {
      let value = {};
      const data = new Uint8Array(evt.data.buffer);
      if (data[0] == 0xaa && data[1] == 0xfa) {
        // 设备通知数据
        if (data[8] == 0xd0) {
          value = { battery: data[9], charge_flag: data[10] };
          const listener = this.onListeners.find(
            (listener) => listener.name == "battery"
          );
          listener && listener.fb(value);
        } else {
          value = { dpi: data[9] - 1, reportRate: data[10] - 1 };
          const listener = this.onListeners.find(
            (listener) => listener.name == "statu"
          );
          listener && listener.fb(value);
        }
      }

      if (data[0] == 0x13 && data[1] == 0xe2) {
        const listener = this.onListeners.find(
          (listener) => listener.name == "match"
        );
        listener && listener.fb(value);
      }
    };
    this.api.getHID().addListeners(fn);
  }

  // 获取报告ID
  getReportId() {
    return this.api.getHID().reportId;
  }

  // 获取连接模式
  async getConnectMode() {
    return this.api.getConnectMode();
  }

  // 设置数据
  async setData(data: number[]) {
    // 设置写入状态标记
    this.isWriting = true;

    // 清除之前的超时
    if (this.writeTimeout) {
      clearTimeout(this.writeTimeout);
    }

    // 设置新的超时，100ms后清除写入状态
    this.writeTimeout = setTimeout(() => {
      this.isWriting = false;
    }, 100);

    return this.api.sendDeviceData(data);
  }

  // 创建延迟函数
  private delay(ms: number): Promise<void> {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  // 开始通讯
  async startComm() {
    const buffer: number[] = new Array(65).fill(0);
    buffer[0] = 0x00;
    buffer[1] = 0x55;
    buffer[2] = 0x01;
    await this.setData(buffer);
  }
  // 结束通讯
  async endComm() {
    const buffer: number[] = new Array(65).fill(0);
    buffer[0] = 0x00;
    buffer[1] = 0x55;
    buffer[2] = 0x02;
    await this.setData(buffer);
  }

  // 获取当前灯光信息
  async getLightInfo() {
    const buffer: number[] = new Array(65).fill(0);
    buffer[0] = 0x00;
    buffer[1] = 0x55;
    buffer[2] = 0x05;
    buffer[5] = 0x20;
    const data = await this.setData(buffer);
    // 最开始插入0
    data.unshift(0);
    const lightInfo: LightInfo = {
      name: "",
      lang: "",
      status: data[9],
      type: data[10],
      mode: data[11],
      brightness: data[12],
      speed: 4 - data[13],
      direction: data[14],
      colorIndex: data[15],
      colorful: data[16],
      colorValue: data[19] || data[18] << 8 || data[17] << 16,
      lockWin: data[26] & 0x01,
      lockAltF4: (data[26] & 0x04) >> 2,
      lockAltTab: (data[26] & 0x02) >> 1,
    };
    return lightInfo;
  }

  // 设置灯光信息
  async setLightInfo(lightInfo: LightInfo) {
    // 开始通讯
    await this.startComm();

    const buffer: number[] = new Array(65).fill(0);
    buffer[0] = 0x00;
    buffer[1] = 0x55;
    buffer[2] = 0x05;
    buffer[5] = 0x20;
    let data = await this.setData(buffer);
    // 最开始插入0
    data.unshift(0);
    data[0] = 0x00;
    data[1] = 0x55;
    data[2] = 0x06;
    data[5] = 0x20;

    data[9] = lightInfo.status;
    data[10] = lightInfo.type;
    data[11] = lightInfo.mode;
    data[12] = lightInfo.brightness;
    data[13] = 4 - lightInfo.speed;
    data[14] = lightInfo.direction;
    data[15] = lightInfo.colorful;
    data[17] = (lightInfo.colorValue >> 16) & 0xff;
    data[18] = (lightInfo.colorValue >> 8) & 0xff;
    data[19] = lightInfo.colorValue & 0xff;

    // 设置锁定状态
    data[26] = 0; // 先清零
    if (lightInfo.lockWin) {
      data[26] |= 0x01; // bit 0
    }
    if (lightInfo.lockAltTab) {
      data[26] |= 0x02; // bit 1
    }
    if (lightInfo.lockAltF4) {
      data[26] |= 0x04; // bit 2
    }

    await this.setData(data);

    // 结束通讯
    await this.endComm();
  }

  // 设置锁Win键
  async setLockWin(lockWin: boolean) {
    // 开始通讯
    await this.startComm();

    const buffer: number[] = new Array(65).fill(0);
    buffer[0] = 0x00;
    buffer[1] = 0x55;
    buffer[2] = 0x05;
    buffer[5] = 0x20;
    let data = await this.setData(buffer);
    // 最开始插入0
    data.unshift(0);
    data[0] = 0x00;
    data[1] = 0x55;
    data[2] = 0x06;
    data[5] = 0x20;

    // 设置锁Win键 - bit 0
    if (lockWin) {
      data[26] = data[26] | 0x01; // 设置bit 0
    } else {
      data[26] = data[26] & 0xfe; // 清除bit 0
    }
    await this.setData(data);

    // 结束通讯
    await this.endComm();
  }

  // 设置Alt+F4键
  async setLockAltF4(lockAltF4: boolean) {
    // 开始通讯
    await this.startComm();

    const buffer: number[] = new Array(65).fill(0);
    buffer[0] = 0x00;
    buffer[1] = 0x55;
    buffer[2] = 0x05;
    buffer[5] = 0x20;
    let data = await this.setData(buffer);
    // 最开始插入0
    data.unshift(0);
    data[0] = 0x00;
    data[1] = 0x55;
    data[2] = 0x06;
    data[5] = 0x20;

    // 设置Alt+F4键 - bit 2
    if (lockAltF4) {
      data[26] = data[26] | 0x04; // 设置bit 2
    } else {
      data[26] = data[26] & 0xfb; // 清除bit 2 (0xFB = 11111011)
    }
    await this.setData(data);

    // 结束通讯
    await this.endComm();
  }

  // 设置锁Alt+Tab键
  async setLockAltTab(lockAltTab: boolean) {
    // 开始通讯
    await this.startComm();

    const buffer: number[] = new Array(65).fill(0);
    buffer[0] = 0x00;
    buffer[1] = 0x55;
    buffer[2] = 0x05;
    buffer[5] = 0x20;
    let data = await this.setData(buffer);
    // 最开始插入0
    data.unshift(0);
    data[0] = 0x00;
    data[1] = 0x55;
    data[2] = 0x06;
    data[5] = 0x20;

    // 设置锁Alt+Tab键 - bit 1
    if (lockAltTab) {
      data[26] = data[26] | 0x02; // 设置bit 1
    } else {
      data[26] = data[26] & 0xfd; // 清除bit 1 (0xFD = 11111101)
    }
    await this.setData(data);

    // 结束通讯
    await this.endComm();
  }

  // 设置按键信息
  async setAllKeyInfo(keyInfo: KeyInfo[]) {
    console.log("setAllKeyFunc", keyInfo);
    // 建议添加数据验证
    if (keyInfo.some((key) => key.index >= 128)) {
      throw new Error("按键索引超出范围");
    }

    // 开始通讯
    await this.startComm();

    // 创建一个512字节的数组来存储所有按键数据
    const allKeyData: number[] = new Array(1024).fill(0);

    // 将按键数据填充到数组中，每个按键占6字节
    for (let i = 0; i < keyInfo.length && i < 128; i++) {
      const offset = keyInfo[i].index * 8;
      allKeyData[offset] = keyInfo[i].type;
      allKeyData[offset + 1] = keyInfo[i].code1;
      allKeyData[offset + 2] = keyInfo[i].code2;
      allKeyData[offset + 3] = keyInfo[i].code3;
      allKeyData[offset + 4] = keyInfo[i].fnType || 0;
      allKeyData[offset + 5] = keyInfo[i].fnCode1 || 0;
      allKeyData[offset + 6] = keyInfo[i].fnCode2 || 0;
      allKeyData[offset + 7] = keyInfo[i].fnCode3 || 0;
    }
    console.log("allKeyData", allKeyData);
    // 计算需要发送的包数（每包56字节）
    const chunkSize = 56;
    const totalChunks = Math.ceil(896 / chunkSize);

    // 分块发送数据
    for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
      const buffer: number[] = new Array(65).fill(0);

      // 设置包头
      buffer[0] = 0x00; // 标志位
      buffer[1] = 0x55; // 固定值
      buffer[2] = 0x09; // 命令
      buffer[3] = 0x02; // 键盘/鼠标
      buffer[4] = 0x00; // 检验和
      buffer[5] = 0x38; // 数据长度
      buffer[6] = (0x38 * chunkIndex) & 0xff; // 地址 - L
      buffer[7] = (0x38 * chunkIndex) >> 8; // 地址 - H
      buffer[8] = 0x00; // 固定值

      // 计算当前块的起始位置和大小
      const startPos = chunkIndex * chunkSize;
      const currentChunkSize = Math.min(chunkSize, 896 - startPos);

      // 复制当前块的数据
      for (let i = 0; i < currentChunkSize; i++) {
        buffer[9 + i] = allKeyData[startPos + i];
      }

      // 发送数据
      await this.setData(buffer);
      // 添加短暂延迟，避免发送太快
      await this.delay(10);
    }

    // 结束通讯
    await this.endComm();
  }

  // 设置按键颜色
  async setKeyColor(keyColor: KeyColor[]) {
    console.log("setKeyColor", keyColor);

    // 建议添加数据验证
    if (keyColor.some((key) => key.index >= 128)) {
      throw new Error("按键索引超出范围");
    }

    // 开始通讯
    await this.startComm();

    // 创建一个384字节的数组来存储所有按键数据
    const allKeyData: number[] = new Array(384).fill(0);

    // 将按键数据填充到数组中，每个按键占6字节
    for (let i = 0; i < keyColor.length && i < 128; i++) {
      const offset = keyColor[i].index * 3;
      const colorValue = parseInt(keyColor[i].keyColor.replace("#", "0x"), 16);
      allKeyData[offset] = (colorValue >> 16) & 0xff; // R (红色)
      allKeyData[offset + 1] = (colorValue >> 8) & 0xff; // G (绿色)
      allKeyData[offset + 2] = colorValue & 0xff; // B (蓝色)
    }
    console.log("allKeyData", allKeyData);
    // 计算需要发送的包数（每包56字节）
    const chunkSize = 56;
    const totalChunks = Math.ceil(384 / chunkSize);

    // 分块发送数据
    for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
      const buffer: number[] = new Array(65).fill(0);

      // 设置包头
      buffer[0] = 0x00; // 标志位
      buffer[1] = 0x55; // 固定值
      buffer[2] = 0x0b; // 命令
      buffer[3] = 0x02; // 键盘/鼠标
      buffer[4] = 0x00; // 检验和
      buffer[5] = 0x38; // 数据长度
      buffer[6] = (0x38 * chunkIndex) & 0xff; // 地址 - L
      buffer[7] = (0x38 * chunkIndex) >> 8; // 地址 - H
      buffer[8] = 0x00; // 固定值

      // 计算当前块的起始位置和大小
      const startPos = chunkIndex * chunkSize;
      const currentChunkSize = Math.min(chunkSize, 384 - startPos);

      // 复制当前块的数据
      for (let i = 0; i < currentChunkSize; i++) {
        buffer[9 + i] = allKeyData[startPos + i];
      }

      // 发送数据
      await this.setData(buffer);
      // 添加短暂延迟，避免发送太快
      await this.delay(10);
    }

    // 结束通讯
    await this.endComm();
  }

  async startMusicalGroove() {
    const buffer: number[] = new Array(65).fill(0);
    buffer[0] = 0x00;
    buffer[1] = 0x55;
    buffer[2] = 0xdc;
    buffer[3] = 0x01;
    await this.setData(buffer);
  }

  async stopMusicalGroove() {
    const buffer: number[] = new Array(65).fill(0);
    buffer[0] = 0x00;
    buffer[1] = 0x55;
    buffer[2] = 0xdc;
    buffer[3] = 0x00;
    await this.setData(buffer);
  }
  // 设置音乐律动
  async setMusicalGroove(keyColors: KeyColor[]): Promise<boolean> {
    if (this.isMusicalGrooveEnd) {
      return false;
    }
    this.isMusicalGrooveEnd = true;
    try {
      // 开始通讯
      await this.startComm();
      console.log("keyColors111", keyColors);

      // 准备 512 字节 (128 * 4)
      const allKeyData = new Array(512).fill(0);
      // 规范化到 0..127 索引
      for (let i = 0; i < keyColors.length; i++) {
        const kc = keyColors[i];
        const off = kc.index * 4;
        const colorString = kc.keyColor || "";

        // 使用新的颜色解析器
        const { r, g, b, a } = parseColorToRGBA(colorString);
        console.log("r, g, b, a", r, g, b, a);

        // 写入 RGBA
        allKeyData[off] = r;
        allKeyData[off + 1] = g;
        allKeyData[off + 2] = b;
        allKeyData[off + 3] = a;
      }

      const chunkSize = 56;
      const dataSize = 109 * 4;
      const totalChunks = Math.ceil(dataSize / chunkSize);

      for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
        const buffer: number[] = new Array(65).fill(0);
        buffer[0] = 0x00; // 报告前导
        buffer[1] = 0x55;
        buffer[2] = 0xdd; // 音乐律动命令
        buffer[3] = 0x02; // 设备类型按 0x00 发送
        buffer[4] = 0x00; // 校验
        buffer[5] = 0x38; // 数据长度(56)
        const offset = shiftFrom16Bit(chunkIndex * 0x38);
        buffer[6] = offset[0]; // 地址 - L
        buffer[7] = offset[1]; // 地址 - H
        buffer[8] = 0x00;

        const startPos = chunkIndex * chunkSize;
        const currentChunkSize = Math.min(chunkSize, dataSize - startPos);
        // 包长度要实际计算，要等齐
        buffer[5] = currentChunkSize;

        for (let i = 0; i < currentChunkSize; i++) {
          buffer[9 + i] = allKeyData[startPos + i];
        }
        console.log("buffer===", chunkIndex, bufferToHexArray(buffer));

        await this.setData(buffer);
        await this.delay(6);
      }

      return true;
    } catch (e) {
      console.error("发送音乐律动数据失败:", e);
      return false;
    } finally {
      await this.endComm();
      this.isMusicalGrooveEnd = false;
    }
  }

  // 获取设备信息
  async getDeviceInfo() {
    await this.delay(33);
    const buffer: number[] = new Array(65).fill(0);
    buffer[0] = 0x00; // 标志位
    buffer[1] = 0x55; // 固定值
    buffer[2] = 0x03; // 命令
    buffer[3] = 0x02; // 键盘/鼠标
    buffer[4] = 0x00; // 检验和
    buffer[5] = 0x38; // 数据长度
    buffer[6] = 0x00; // 地址 - L
    buffer[7] = 0x00; // 地址 - H
    buffer[8] = 0x00; // 固定值
    const data = await this.setData(buffer);
  }

  // 获取设备版本信息
  async getDeviceVersion() {
    await this.delay(33);
    const buffer: number[] = new Array(65).fill(0);

    buffer[0] = 0x00;
    buffer[1] = 0x55;
    buffer[2] = 0x03;
    const data: number[] = await this.api.sendDeviceData(buffer);

    let deviceVersion = ""; // ASCII码 '0'=48, '9'=57
    if (data[23] >= 48 && data[23] <= 57) {
      deviceVersion += String.fromCharCode(data[23]);
      deviceVersion += ".";
    } else deviceVersion += "0.";

    if (data[24] >= 48 && data[24] <= 57) {
      deviceVersion += String.fromCharCode(data[24]);
      deviceVersion += ".";
    } else deviceVersion += "0.";

    if (data[25] >= 48 && data[25] <= 57) {
      deviceVersion += String.fromCharCode(data[25]);
    } else deviceVersion += "0";

    return { version: deviceVersion };
  }

  // 获取电量
  async getBatteryInfo() {
    await this.delay(33);
    const buffer: number[] = new Array(65).fill(0);

    buffer[0] = 0x00;
    buffer[1] = 0x55;
    buffer[2] = 0x30;
    buffer[3] = 0xa5;
    buffer[4] = 0x0b;
    buffer[5] = 0x2e;
    buffer[6] = 0x01;
    buffer[7] = 0x01;
    buffer[8] = 0x01;

    buffer[9] = 0x00;
    buffer[10] = 0x00;

    let data = await this.api.sendDeviceData(buffer);
    if (buffer[1] !== 0x30) {
      await new Promise((resolve) => setTimeout(resolve, 100));
      data = await this.api.sendDeviceData(buffer);
      if (data[1] !== 0x30) {
        await new Promise((resolve) => setTimeout(resolve, 100));
        data = await this.api.sendDeviceData(buffer);
      }
    }
    if (data[1] === 0x30) {
      return { battery_value: data[8], charge_flag: data[9] };
    }
    return { battery_value: 100, charge_flag: 0 };
  }

  // 获取设备默认矩阵信息
  async getDefaultMatrix(layer: number) {
    const bufferSize = 56;
    const keySize = 512;
    let keyData: number[] = [];
    for (let offset = 0; offset < keySize; offset += bufferSize) {
      const size = Math.min(keySize - offset, bufferSize);
      const [lo, hi] = shiftFrom16Bit(offset);
      const checkSum = 0;

      const buffer: number[] = new Array(65).fill(0);
      buffer[0] = 0x00; // 标志位
      buffer[1] = 0x55; // 固定值
      buffer[2] = 0x07; // 命令
      buffer[3] = 0x02; // 键盘/鼠标
      buffer[4] = checkSum; // 检验和
      buffer[5] = size; // 数据长度
      buffer[6] = lo; // 地址 - L
      buffer[7] = hi; // 地址 - H
      buffer[8] = 0x00; // 固定值

      await this.delay(16);
      const data = await this.setData(buffer);
      keyData = keyData.concat(data.slice(8));
    }
    //console.log("getKeyMatrixData keyData", keyData);

    // 解析按键数据
    // const maxKeyCnt = 128;
    // let newKeyInfos = [];
    // for (let i = 0; i < maxKeyCnt; i++) {
    //   const [type, code1, code2] = keyData.slice(i * 3, i * 3 + 3);
    //   if (type == 0x10 || type == 0x50) {
    //     const code = getKeyCode(type, code1, code2);
    //     const name = getKeyName({ type, code1, code2 });
    //     newKeyInfos.push({
    //       type,
    //       code1,
    //       code2,
    //       code,
    //       name,
    //       profile: 1,
    //       layer: 0,
    //     });
    //   } else {
    //     const name = getKeyName({ type, code1, code2 }) || "";
    //     newKeyInfos.push({
    //       type: type,
    //       code1: code1,
    //       code2: code2,
    //       code: 0,
    //       name,
    //       profile: 1,
    //       layer: 0,
    //     });
    //   }
    // }
    //console.log("getKeyMatrixData newKeyInfos", newKeyInfos);
    return keyData;
  }

  // 获取用户按键矩阵信息
  async getUserMatrix(layer: number) {
    const bufferSize = 56;
    const keySize = 512;
    let keyData: number[] = [];
    for (let offset = 0; offset < keySize; offset += bufferSize) {
      const size = Math.min(keySize - offset, bufferSize);
      const [lo, hi] = shiftFrom16Bit(offset);
      const checkSum = 0;

      const buffer: number[] = new Array(65).fill(0);
      buffer[0] = 0x00; // 标志位
      buffer[1] = 0x55; // 固定值
      buffer[2] = 0x08; // 命令
      buffer[3] = 0x02; // 键盘/鼠标
      buffer[4] = checkSum; // 检验和
      buffer[5] = size; // 数据长度
      buffer[6] = lo; // 地址 - L
      buffer[7] = hi; // 地址 - H
      buffer[8] = 0x00; // 固定值

      await this.delay(16);
      const data = await this.setData(buffer);
      keyData = keyData.concat(data.slice(8));
    }
  }

  // 恢复键盘出厂设置
  async restoreKeyboardFactorySettings(reportId: number = 0) {
    const buffer: number[] = new Array(65).fill(0);
    buffer[0] = 0x00; // 标志位
    buffer[1] = 0x55; // 固定值
    buffer[2] = 0xee; // 命令
    await this.setData(buffer);
  }

  async setMacro(macroList: MacroProfile[]) {
    // 开始通讯
    await this.startComm();

    const macroAddr = new Array(64).fill(0);
    let macroContentSize = 0;
    const newMacroList: any = [];
    macroList.map((macroProfile, index) => {
      const newMacroActions: any = [];
      for (let i = 0; i < macroProfile.list.length; i++) {
        const action = macroProfile.list[i];
        if (action.type == 2) {
          const code = action.code;
          newMacroActions.push({
            code,
            type: 2,
            action: action.action,
            delay: action?.delay || 10,
          });
        }
        if (action.type == 1) {
          let code = action.code;
          if (action.code == 0) {
            code = 0x01;
          } else if (action.code == 1) {
            code = 0x04;
          } else if (action.code == 2) {
            code = 0x02;
          } else if (action.code == 3) {
            code = 0x08;
          } else if (action.code == 4) {
            code = 0x10;
          }
          newMacroActions.push({
            code,
            type: 3,
            action: action.action,
            delay: action?.delay || 10,
          });
        }
      }
      newMacroList.push({
        type: macroProfile.type,
        list: newMacroActions,
      });
      if (newMacroActions.length) {
        const addr = shiftFrom16Bit(macroContentSize + 64);
        macroAddr[index * 2] = addr[0];
        macroAddr[index * 2 + 1] = addr[1];
        macroContentSize += newMacroActions.length * 4;
      } else {
        macroAddr[index * 2] = 0x40;
        macroAddr[index * 2 + 1] = 0x00;
      }
    });

    const macroContent = new Array(macroContentSize).fill(0);
    let macroActionOffset = 0;
    newMacroList.map((macroProfile: any) => {
      macroProfile.list.map((macroAction: any, actionIndex: number) => {
        const offset = shiftFrom16Bit(macroAction.delay || 2);
        const end = actionIndex == macroProfile.list.length - 1 ? 1 : 0;
        const action = macroAction.action;
        //const type = (macroAction.code >= 0xe0 ? 1 : (macroAction.type)) | (action << 6) | (end << 7);
        const type = macroAction.type | (action << 6) | (end << 7);

        macroContent[macroActionOffset] = offset[0];
        macroContent[macroActionOffset + 1] = offset[1];
        macroContent[macroActionOffset + 2] = type;
        //macroContent[macroActionOffset + 3] = macroAction.code >= 0xe0 ? (0x1 << (macroAction.code & 0x0F)) : macroAction.code;
        macroContent[macroActionOffset + 3] = macroAction.code;
        macroActionOffset += 4;
      });
    });
    const data = [...macroAddr, ...macroContent];
    const layerSize = 4096;
    const dataSlice = _.chunk(data, 56);
    for (let index = 0; index < dataSlice.length; index++) {
      const offset = shiftFrom16Bit(index * 56);
      const dataArr = [
        dataSlice[index].length,
        offset[0],
        offset[1],
        0x0,
        ...dataSlice[index],
      ];
      const checkSum = dataArr.reduce((p, c) => p + c) & 0xff;
      await this.setData([0x00, 0x55, 0x0d, 0x0, checkSum, ...dataArr]);
    }
    await this.setData([0x00, 0x55, 0x10, 0xa5]);
    // 结束通讯
    await this.endComm();
  }
}
